package com.vegetable.modules.service.stock.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.vegetable.modules.entity.stock.CostWeightChangeSource;
import com.vegetable.modules.service.stock.IChainViewService;
import com.vegetable.modules.service.stock.ICostWeightChangeSourceService;
import com.vegetable.modules.vo.CostWeightChangeChainVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 连锁变化链路视图服务实现类
 * </p>
 *
 * @author wangruijie
 * @since 2024-03-21
 */
@Slf4j
@Service
public class ChainViewServiceImpl implements IChainViewService {

    @Autowired
    private ICostWeightChangeSourceService costWeightChangeSourceService;

    @Override
    public CostWeightChangeChainVO buildChainView(CostWeightChangeSource rootChange) {
        CostWeightChangeChainVO chainVO = new CostWeightChangeChainVO();
        chainVO.setRootChange(rootChange);

        // 获取所有连锁变化节点
        List<CostWeightChangeSource> chainChanges = getAllChainNodes(rootChange);
        chainVO.setChainChanges(chainChanges);

        // 计算链路深度
        chainVO.setChainDepth(calculateChainDepth(chainChanges));

        // 计算影响的库存数量
        chainVO.setAffectedStockCount(calculateAffectedStockCount(chainChanges));

        // 计算总成本变化金额
        chainVO.setTotalChangeAmount(calculateTotalChangeAmount(chainChanges));

        return chainVO;
    }

    @Override
    public CostWeightChangeChainVO buildChainViewBySourceOrder(Long sourceOrderId) {
        // 查找源头变化记录
        QueryWrapper<CostWeightChangeSource> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("source_order_id", sourceOrderId);
        queryWrapper.eq("source_type", 1); // 订单价格修改作为源头
        List<CostWeightChangeSource> rootChanges = costWeightChangeSourceService.list(queryWrapper);

        if (!rootChanges.isEmpty()) {
            // 使用第一个作为源头
            return buildChainView(rootChanges.get(0));
        }

        return new CostWeightChangeChainVO();
    }

    @Override
    public List<CostWeightChangeSource> getAllChainNodes(CostWeightChangeSource rootChange) {
        List<CostWeightChangeSource> chainNodes = new ArrayList<>();

        // 递归查找所有连锁变化节点
        findChainNodesRecursive(rootChange, chainNodes);

        // 按操作时间排序
        return chainNodes.stream()
                .sorted((c1, c2) -> c1.getOperateTime().compareTo(c2.getOperateTime()))
                .collect(Collectors.toList());
    }

    /**
     * 递归查找连锁变化节点
     */
    private void findChainNodesRecursive(CostWeightChangeSource currentChange, List<CostWeightChangeSource> chainNodes) {
        // 添加当前节点
        chainNodes.add(currentChange);

        // 查找由当前变化引起的其他变化
        QueryWrapper<CostWeightChangeSource> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("source_order_id", currentChange.getSourceOrderId());
        // 排除当前节点本身
        queryWrapper.ne("id", currentChange.getId());

        List<CostWeightChangeSource> relatedChanges = costWeightChangeSourceService.list(queryWrapper);

        // 递归处理相关变化
        for (CostWeightChangeSource relatedChange : relatedChanges) {
            // 避免重复添加
            if (!chainNodes.contains(relatedChange)) {
                findChainNodesRecursive(relatedChange, chainNodes);
            }
        }
    }

    /**
     * 计算链路深度
     */
    private Integer calculateChainDepth(List<CostWeightChangeSource> chainChanges) {
        // 简化计算，实际项目中可以根据业务逻辑进行更复杂的计算
        return chainChanges.size();
    }

    /**
     * 计算影响的库存数量
     */
    private Integer calculateAffectedStockCount(List<CostWeightChangeSource> chainChanges) {
        // 统计不同的库存ID数量
        return (int) chainChanges.stream()
                .map(CostWeightChangeSource::getStockId)
                .distinct()
                .count();
    }

    /**
     * 计算总成本变化金额
     */
    private BigDecimal calculateTotalChangeAmount(List<CostWeightChangeSource> chainChanges) {
        return chainChanges.stream()
                .map(CostWeightChangeSource::getChangeAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}